<?php


namespace app\api\service;


use app\api\model\OrderProduct;
use app\api\model\Product;
use app\api\model\UserAddress;
use app\lib\enum\OrderStatusEnum;
use app\lib\exception\orderException;
use app\lib\exception\UserException;
use think\Db;
use think\Exception;

class Order{
    //订单的商品列表，客户端传递过来的products参数
    protected $oProducts;

    //真实的商品信息(包括库存量)
    protected $products;

    protected $uid;


    /**
     * @param $uid  谁下的单
     * @param $oProducts  下单的商品和数量是多少
     * @return array
     *
     * 从提交数据到下单成功有那些步骤
     * 1.从数据库中获取传入的商品，进行数量的比对，如果满足则继续往下走
     * 2.
     *
     *
     */


    //下单
    public function place($uid,$oProducts){
        //查询出数量进行对比，看看是否有库存
        $this->oProducts = $oProducts;//传入的数据
        $this->products = $this->getProductsByOrder($oProducts);//获取数据库中商品信息，主要就是获取到商品的数量
        $this->uid = $uid;
        $status = $this->getOrderStatus();//进行购买商品数量的比较
        if(!$status['pass']){//订单状态没有通过，即购买的某件商品的数量不够了
            $status['order_id'] = -1;
            return $status;
        }
        //获取插入订单数据库中的数据
        $orderSnap = $this->snapOrder($status);
        //生成订单,返回订单id 订单编号 订单创建时间
        $list = $this->createOrder($orderSnap);
        $list['pass'] = true;//订单库存量检测通过
        return $list;
    }

    //创建订单
    private function createOrder($snap){
        Db::startTrans();//开始事物，防止出现数据已经写入订单表了，但是写入订单商品表失败，认为他是一个事物
        try{
            /**
             * 订单表 和订单商品表 是一对多的关系，一个订单中可以购买多个商品
             * 一对多的模型关系中，先做简单的一，在做多的部分
             *
             */
            $orderNo = self::makeOrderNo();
            $order = new \app\api\model\Order();
            $order->user_id = $this->uid;
            $order->order_no = $orderNo;
            $order->total_price = $snap['orderPrice'];
            $order->total_count = $snap['totalCount'];
            $order->snap_img = $snap['snapImg'];
            $order->snap_name = $snap['snapName'];
            $order->snap_address = $snap['snapAddress'];
            $order->snap_items = json_encode($snap['pStatus']);

            //将数据写入数据库
            $order->save();
            /**
             * 订单生成后，获取这条订单的id号，用于创建订单商品表
             * 订单商标表中包含着订单id以及这条订单对应的那几件商品
             */

            //获取订单id
            $orderId = $order->id;
            $create_time = $order->create_time;
            $totalPrice = $order->total_price;
            foreach ($this->oProducts as &$p){
                $p['order_id'] = $orderId;
            }

            $orderProduct = new OrderProduct();
            $orderProduct->saveAll($this->oProducts);
            Db::commit();
            return [
                'order_no' =>$orderNo,
                'order_id' =>$orderId,
                'totalPrice' =>$totalPrice,
                'create_time' => $create_time,
            ];
        }catch (Exception $exception){
            Db::rollback();//出现了错误，立马回滚
            throw $exception;
        }





    }

    //生成订单，返回订单编号
    public static function makeOrderNo()
    {
        $yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
        $orderSn =
            $yCode[intval(date('Y')) - 2017] . strtoupper(dechex(date('m'))) . date(
                'd') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf(
                '%02d', rand(0, 99));
        return $orderSn;
    }

    //生成订单快照(订单记录)
    private function snapOrder($status){
        $snap = array(
            'orderPrice' => 0,
            'totalCount' => 0,
            'pStatus' => [],
            'snapAddress' =>'', //订单地址
            'snapName' =>'', //多个商品的订单中选择一个作为展示在订单列表中的名字
            'snapImg' =>''  //多个商品的订单中选择一个作为展示在订单列表中的缩略图
        );
        $snap['orderPrice'] = $status['orderPrice'];
        $snap['totalCount'] = $status['totalCount'];
        $snap['pStatus'] = $status['pStatusArray'];
        $snap['snapAddress'] = json_encode($this->getUserAddress());
        $snap['snapName'] = $this->products[0]['name'];
        $snap['snapImg'] = $this->products[0]['main_img_url'];
        if(count($this->products) >1){
            $snap['snapName'] .='等商品';
        }
        return $snap;
    }

    //获取数据库中的地址
    private function getUserAddress(){
        $userAddress = new UserAddress();
        $list = $userAddress::where('user_id','=',$this->uid)->find();
        if(!$list){
            throw  new UserException([
                'msg'=>'用户收货地址不存在,下单失败',
                'errorCode'=>60001,
            ]);
        }

        return $list->toArray();
    }

    //订单状态：即通过了商品数量的检测后，成功获取订单的信息
    private function getOrderStatus(){
        $status = array(
            'pass' =>true,
            'orderPrice'=>0,
            'totalCount' =>0,
            'pStatusArray'=>[]
        );
        foreach ($this->oProducts as $oProduct){
            $pStatus = $this->getProductStatus($oProduct['product_id'],$oProduct['count'],$this->products);
            if(!$pStatus['haveStock']){
                $status['pass'] = false;
            }
            $status['orderPrice'] +=$pStatus['totalPrice'];
            $status['totalCount'] +=$pStatus['count'];
            array_push($status['pStatusArray'],$pStatus);
        }

        return $status;
    }

    //检测某商品库存中的数量是否大于购买的数量，如果购买的数量大于库存，则表示没有货了，此次订单不能生成
    private function getProductStatus($oPID,$oCount,$products){
        $pIndex = -1;
        //每个订单下的商品的详细信息
        $pStatus = [
            'id' =>null, //商品id
            'haveStock' => false, //是否有库存
            'count' =>0, //传入购买的数量
            'totalPrice' =>0
        ];
        //传入的id在查询的商品列表中存在，则获取该id的商品详情
        for($i=0;$i<count($products);$i++){
            if($oPID == $products[$i]['id']){//如果$oPID在商品中，则获取该$oPID是在商品列表中的具体位置，并记录下表
                $pIndex = $i;
            }
        }

        if($pIndex == -1){
            //客户端传递的商品可能不存在
            throw new orderException(['msg'=>'id为'.$oPID.'商品不存在，创建订单失败']);
        }else{
            $pStatus['id'] = $products[$pIndex]['id'];
            $pStatus['count'] = $oCount;
            $pStatus['name'] = $products[$pIndex]['name'];
            $pStatus['totalPrice'] = $products[$pIndex]['price'] * $oCount;
            if(($products[$pIndex]['stock'] - $oCount) >=0){
                $pStatus['haveStock'] = true;
            }else{
                throw new orderException(['msg'=>$products[$pIndex]['name'].'，库粗不足']);
            }
        }

        return $pStatus;

    }

    //获取商品信息
    private function getProductsByOrder($oProducts){
        $oPIDS = array();
        foreach ($oProducts as $item){
            $oPIDS[] = $item['product_id'];
        }
        //查询数据库中的数据
        $products = Product::all($oPIDS)->visible(['id','price','stock','name','main_img_url'])->toArray();
        return $products;
    }

    //接受pay方法传入的$orderId来做商品数量的验证,pay中的调用次方法进行库存量检测
    public function checkOrderStock($orderId){
        //获取订单商品表中数据,从前台传入的购买的商品
        $oProducts = OrderProduct::where('order_id',$orderId)->select();
        $this->oProducts = $oProducts;
        //数据库中的商品
        $this->products = $this->getProductsByOrder($this->oProducts);
        $status = $this->getOrderStatus();
        return $status;

    }

    //发货
    public function delivery($orderID, $jumpPage = '')
    {
        $orderModel = new \app\api\model\Order();
        $order = $orderModel::where('id', '=', $orderID)
            ->find();
        if (!$order) {
            throw new OrderException();
        }
        if ($order->status != OrderStatusEnum::PAID) {
            throw new OrderException([
                'msg' => '还没付款呢，想干嘛？或者你已经更新过订单了，不要再刷了',
                'errorCode' => 80002,
                'code' => 403
            ]);
        }
        $order->status = OrderStatusEnum::DELIVERED;
        //$order->save();

        //发送模板消息
        $message = new DeliveryMessage();
        return $message->sendDeliveryMessage($order, $jumpPage);
    }


}













